import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';

enum LinearStrokeCap { butt, round, roundAll }

// ignore: must_be_immutable
class MyLinearPercentIndicator extends StatefulWidget {
  ///Percent value between 0.0 and 1.0
  final double percent;
  final double width;

  final double minProgress;

  ///Height of the line
  final double lineHeight;

  ///Color of the background of the Line , default = transparent
  final Color fillColor;

  ///First color applied to the complete line
  final Color backgroundColor;

  ///Color of the Container of the Line
  final Color borderColor;

  Color get progressColor => _progressColor;

  Color _progressColor;

  ///true if you want the Line to have animation
  final bool animation;

  ///duration of the animation in milliseconds, It only applies if animation attribute is true
  final int animationDuration;

  ///widget at the left of the Line
  final Widget leading;

  ///widget at the right of the Line
  final Widget trailing;

  ///widget inside the Line
  final Widget center;

  ///The kind of finish to place on the end of lines drawn, values supported: butt, round, roundAll
  final LinearStrokeCap linearStrokeCap;

  ///alignment of the Row (leading-widget-center-trailing)
  final MainAxisAlignment alignment;

  ///padding to the LinearPercentIndicator
  final EdgeInsets padding;

  /// set true if you want to animate the linear from the last percent value you set
  final bool animateFromLastPercent;

  /// If present, this will make the progress bar colored by this gradient.
  ///
  /// This will override [progressColor]. It is an error to provide both.
  final LinearGradient linearGradient;

  /// set false if you don't want to preserve the state of the widget
  final bool addAutomaticKeepAlive;

  /// set true if you want to animate the linear from the right to left (RTL)
  final bool isRTL;
  final bool isRound;

  /// Creates a mask filter that takes the progress shape being drawn and blurs it.
  final MaskFilter maskFilter;

  /// Set true if you want to display only part of [linearGradient] based on percent value
  /// (ie. create 'VU effect'). If no [linearGradient] is specified this option is ignored.
  final bool clipLinearGradient;

  /// set a linear curve animation type
  final Curve curve;

  /// set true when you want to restart the animation, it restarts only when reaches 1.0 as a value
  /// defaults to false
  final bool restartAnimation;

  MyLinearPercentIndicator(
      {Key key,
      this.isRound = true,
      this.fillColor = Colors.transparent,
      this.percent = 0.0,
      this.lineHeight = 5.0,
      this.width,
      this.backgroundColor = const Color(0xFFB8C7CB),
      this.linearGradient,
      Color progressColor,
      this.animation = false,
      this.animationDuration = 500,
      this.animateFromLastPercent = false,
      this.isRTL = false,
      this.leading,
      this.trailing,
      this.center,
      this.addAutomaticKeepAlive = true,
      this.linearStrokeCap,
      this.padding = const EdgeInsets.symmetric(horizontal: 10.0),
      this.alignment = MainAxisAlignment.start,
      this.maskFilter,
      this.clipLinearGradient = false,
      this.curve = Curves.linear,
      this.restartAnimation = false,
      this.borderColor = Colors.transparent, this.minProgress=0.05})
      : super(key: key) {
    if (linearGradient != null && progressColor != null) {
      throw ArgumentError(
          'Cannot provide both linearGradient and progressColor');
    }
    _progressColor = progressColor ?? Colors.red;

    assert(curve != null);

    if (percent < 0.0 || percent > 1.0) {
      throw new Exception("Percent value must be a double between 0.0 and 1.0");
    }
  }

  @override
  _MyLinearPercentIndicatorState createState() =>
      _MyLinearPercentIndicatorState();
}

class _MyLinearPercentIndicatorState extends State<MyLinearPercentIndicator>
    with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
  AnimationController _animationController;
  Animation _animation;
  double _percent = 0.0;

  @override
  void dispose() {
    if (_animationController != null) {
      _animationController.dispose();
    }
    super.dispose();
  }

  @override
  void initState() {
    if (widget.animation) {
      _animationController = new AnimationController(
          vsync: this,
          duration: Duration(milliseconds: widget.animationDuration));
      _animation = Tween(begin: 0.0, end: widget.percent).animate(
        CurvedAnimation(parent: _animationController, curve: widget.curve),
      )..addListener(() {
          setState(() {
            _percent = _animation.value;
          });
          if (widget.restartAnimation && _percent == 1.0) {
            _animationController.repeat(min: 0, max: 1.0);
          }
        });
      _animationController.forward();
    } else {
      _updateProgress();
    }
    super.initState();
  }

  @override
  void didUpdateWidget(MyLinearPercentIndicator oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.percent != widget.percent) {
      if (_animationController != null) {
        _animationController.duration =
            Duration(milliseconds: widget.animationDuration);
        _animation = Tween(
                begin: widget.animateFromLastPercent ? oldWidget.percent : 0.0,
                end: widget.percent)
            .animate(
          CurvedAnimation(parent: _animationController, curve: widget.curve),
        );
        _animationController.forward(from: 0.0);
      } else {
        _updateProgress();
      }
    }
  }

  _updateProgress() {
    setState(() {
      _percent = widget.percent;
    });
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    var items = List<Widget>();
    if (widget.leading != null) {
      items.add(widget.leading);
    }
    final hasSetWidth = widget.width != null;
    var containerWidget = Container(
      width: hasSetWidth ? widget.width : double.infinity,
      height: widget.lineHeight,
      child: CustomPaint(
        painter: LinearPainter(
          isRTL: widget.isRTL,
          progress: _percent,
          minProgress: widget.minProgress,
          radius: widget.isRound ? widget.lineHeight / 2 : 0.0,
          center: widget.center,
          progressColor: widget.progressColor,
          linearGradient: widget.linearGradient,
          backgroundColor: widget.borderColor,
          linearStrokeCap: widget.linearStrokeCap,
          lineWidth: widget.lineHeight,
          maskFilter: widget.maskFilter,
          clipLinearGradient: widget.clipLinearGradient,
        ),
        child: (widget.center != null)
            ? Center(child: widget.center)
            : Container(),
      ),
    );
    if (hasSetWidth) {
      items.add(containerWidget);
    } else {
      items.add(Expanded(
        child: containerWidget,
      ));
    }
    if (widget.trailing != null) {
      items.add(widget.trailing);
    }

    return Material(
      color: Colors.transparent,
      child: new Container(
          child: Row(
        mainAxisAlignment: widget.alignment,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: items,
      )),
    );
  }

  @override
  bool get wantKeepAlive => widget.addAutomaticKeepAlive;
}

class LinearPainter extends CustomPainter {
  final Paint _paintBackground = new Paint();
  final Paint _paintLine = new Paint();
  final lineWidth;
  final progress;
  final center;
  final isRTL;

  ///最外层的圆角
  final double radius;
  final Color progressColor;
  final Color backgroundColor;
  final LinearStrokeCap linearStrokeCap;
  final LinearGradient linearGradient;
  final MaskFilter maskFilter;
  final bool clipLinearGradient;
  final double minProgress;
  LinearPainter({
    this.radius,
    this.lineWidth,
    this.progress,
    this.center,
    this.isRTL,
    this.minProgress,
    this.progressColor,
    this.backgroundColor,
    this.linearStrokeCap = LinearStrokeCap.butt,
    this.linearGradient,
    this.maskFilter,
    this.clipLinearGradient,
  }) {
    _paintBackground.color = backgroundColor;
    _paintBackground.style = PaintingStyle.stroke;
    _paintBackground.strokeWidth = 1;

    _paintLine.color = progress.toString() == "0.0"
        ? progressColor.withOpacity(0.0)
        : progressColor;
    _paintLine.style = PaintingStyle.fill;
    _paintLine.strokeWidth = lineWidth;

//    if (linearStrokeCap == LinearStrokeCap.round) {
//      _paintLine.strokeCap = StrokeCap.round;
//    } else if (linearStrokeCap == LinearStrokeCap.butt) {
//      _paintLine.strokeCap = StrokeCap.butt;
//    } else {
//      _paintLine.strokeCap = StrokeCap.round;
//      _paintBackground.strokeCap = StrokeCap.round;
//    }
  }

  @override
  void paint(Canvas canvas, Size size) {
//    final start = Offset(0.0, size.height / 2);
//    final end = Offset(size.width, size.height / 2);
//    Rect rect = Rect.fromLTRB(0, 0, size.width, size.height);
//    //画圆角背景框
//    RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(20.0));
//    canvas.drawRRect(rrect, _paintBackground);
//
//    //画进度条
//    final xProgress = size.width * progress;
//    Rect rectProgress = Rect.fromLTRB(0, 0, xProgress, size.height);
//    RRect rrectProgress = RRect.fromRectAndRadius(rectProgress, Radius.circular(20.0));
//    canvas.drawRRect(rrectProgress, _paintLine);
    // 画path
    Path drawPath(
        double progressHeight, double x, double totalHeight, double r) {
      Path path = new Path();
      //如果间隔存在，而且半径大于0，而且如果进度条的高度大于间隔的直径，半径就取高度的，否则进度条会变形
      double R = r;
      double startY = 0.0;
      double endY = progressHeight;
      startY = (-progressHeight + totalHeight) / 2;
      endY = (progressHeight + totalHeight) / 2;
      // if (progressHeight <= indicatorRadius) {
      //   startY = indicatorRadius - progressHeight / 2;
      //   endY = indicatorRadius + progressHeight / 2;
      // }
      if (r == null || r == 0.0) {
        path
          ..moveTo(0.0, startY)
          ..lineTo(x, startY)
          ..lineTo(x, endY)
          ..lineTo(0.0, endY);
      } else {
        path
          ..moveTo(R, startY)
          ..lineTo(x - R, startY)
          ..arcToPoint(Offset(x - R, endY),
              radius: Radius.circular(R), clockwise: true, largeArc: false)
          ..lineTo(R, endY)
          ..arcToPoint(Offset(R, startY),
              radius: Radius.circular(R), clockwise: true, largeArc: true);
      }
      path..close();
      return path;
    }

// 画进度条


    final Paint paint = Paint()
      ..color = backgroundColor
      ..style = PaintingStyle.stroke;
    final Paint paintProgress = Paint()
      ..color = progressColor
      ..style = PaintingStyle.fill;
    canvas.drawPath(
        drawPath(lineWidth, size.width, size.height,radius), paint);
    if(progress>0){
      canvas.drawPath(
          drawPath(lineWidth, progress>=minProgress?size.width*progress:size.width*minProgress, size.height,radius), paintProgress);
    }
  }



  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
